package com.ssy.lingxi.member.merchant.serviceimpl.web;

import com.querydsl.jpa.impl.JPAQueryFactory;
import com.ssy.lingxi.common.constant.member.MemberStatusEnum;
import com.ssy.lingxi.common.constant.member.MemberTypeEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.member.merchant.api.constant.MemberRelationTypeEnum;
import com.ssy.lingxi.member.merchant.config.ServiceConfig;
import com.ssy.lingxi.member.merchant.entity.MemberRelationDO;
import com.ssy.lingxi.member.merchant.entity.MemberUserDO;
import com.ssy.lingxi.member.merchant.entity.QMemberRelationDO;
import com.ssy.lingxi.member.merchant.model.constant.MemberInnerStatusEnum;
import com.ssy.lingxi.member.merchant.model.constant.MemberOuterStatusEnum;
import com.ssy.lingxi.member.merchant.model.constant.MemberRegisterSourceEnum;
import com.ssy.lingxi.member.merchant.model.constant.MemberStringEnum;
import com.ssy.lingxi.member.merchant.model.vo.basic.request.SubMemberIdRoleIdVO;
import com.ssy.lingxi.member.merchant.model.vo.basic.response.DropdownItem;
import com.ssy.lingxi.member.merchant.model.vo.basic.response.LevelAndTagVO;
import com.ssy.lingxi.member.merchant.model.vo.basic.response.MemberTypeIdAndNameVO;
import com.ssy.lingxi.member.merchant.model.vo.basic.response.RoleIdAndNameVO;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.response.MemberAssignedPageQueryVO;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.response.MemberAssignedSearchConditionVO;
import com.ssy.lingxi.member.merchant.model.vo.validate.request.MemberAbilityAssignedMemberQueryVO;
import com.ssy.lingxi.member.merchant.repository.MemberRelationRepository;
import com.ssy.lingxi.member.merchant.repository.MemberUserRepository;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberCacheService;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberLevelConfigService;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberValidateService;
import com.ssy.lingxi.member.merchant.service.base.IBaseSiteService;
import com.ssy.lingxi.member.merchant.service.web.IMemberAbilityAssignedService;
import com.ssy.lingxi.member.merchant.service.web.IPlatformMemberRoleRuleService;
import com.ssy.lingxi.member.merchant.utils.NumberUtil;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import javax.transaction.Transactional;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 会员能力-会员管理-待分配会员相关接口
 *
 * @author whm
 * @version 2.0.0
 * @date 2022-03-29
 **/
@Service
public class MemberAbilityAssignedServiceImpl implements IMemberAbilityAssignedService {

    @Resource
    private IBaseMemberCacheService memberCacheService;

    @Resource
    private MemberRelationRepository relationRepository;

    @Resource
    private IBaseMemberValidateService baseMemberValidateService;

    @Resource
    private IBaseMemberLevelConfigService baseMemberLevelConfigService;

    @Resource
    private MemberUserRepository memberUserRepository;

    @Resource
    private IPlatformMemberRoleRuleService roleRuleService;

    @Resource
    private IBaseSiteService siteService;

    @Resource
    private JPAQueryFactory jpaQueryFactory;

    private final List<MemberOuterStatusEnum> outerStatusEnums = Stream.of(
            MemberOuterStatusEnum.DEPOSITING,
            MemberOuterStatusEnum.DEPOSITORY_PASSED,
            MemberOuterStatusEnum.DEPOSITORY_NOT_PASSED,
            MemberOuterStatusEnum.MODIFYING,
            MemberOuterStatusEnum.MODIFY_PASSED,
            MemberOuterStatusEnum.MODIFY_NOT_PASSED
    ).collect(Collectors.toList());

    /**
     * 获取分页查询会员列表页面中各个查询条件下拉选择框的内容
     *
     * @param headers HttpHeaders信息
     * @return 操作结果
     */
    @Override
    public Wrapper<MemberAssignedSearchConditionVO> getPageCondition(HttpHeaders headers) {
        UserLoginCacheDTO loginUser = memberCacheService.needLoginFromBusinessPlatform(headers);

        //规则：
        MemberAssignedSearchConditionVO conditionVO = new MemberAssignedSearchConditionVO();
        //内部状态
        List<DropdownItem> itemList = MemberInnerStatusEnum.toDropdownItems();
        itemList.add(0, new DropdownItem(0, MemberStringEnum.CHOOSE.getName()));
        conditionVO.setInnerStatus(itemList);

        //外部状态
        itemList = outerStatusEnums.stream().map(e -> new DropdownItem(e.getCode(), e.getMsg())).collect(Collectors.toList());
        itemList.add(0, new DropdownItem(0, MemberStringEnum.CHOOSE.getName()));
        conditionVO.setOuterStatus(itemList);

        //注册来源
        itemList = MemberRegisterSourceEnum.toAbilityDropdownList();
        itemList.add(0, new DropdownItem(0, MemberStringEnum.CHOOSE.getName()));
        conditionVO.setSources(itemList);

        //会员状态
        itemList = Arrays.stream(MemberStatusEnum.values()).sorted(Comparator.comparingInt(MemberStatusEnum::getCode)).map(e -> new DropdownItem(e.getCode(), e.getMsg())).collect(Collectors.toList());
        itemList.add(0, new DropdownItem(0, MemberStringEnum.CHOOSE.getName()));
        conditionVO.setStatus(itemList);

        //获取是否开启saas多租户部署
        Boolean enableMultiTenancy = siteService.isEnableMultiTenancy(headers).getData();

        List<MemberTypeIdAndNameVO> memberTypeList;
        List<RoleIdAndNameVO> roleList;
        if (enableMultiTenancy) {//有开启
            //会员类型（这里返回的是Id）
            memberTypeList = baseMemberValidateService.getSubMemberTypeList(loginUser.getMemberType(), Optional.ofNullable(roleRuleService.subMemberRoles(loginUser.getMemberId())).map(Wrapper::getData).orElse(new ArrayList<>()));
            //会员角色（按照Id升序排序）
            roleList = baseMemberValidateService.getSubRoleList(loginUser.getMemberType(), Optional.ofNullable(roleRuleService.subMemberRoles(loginUser.getMemberId())).map(Wrapper::getData).orElse(new ArrayList<>()));
        } else {//未开启
            //会员类型（这里返回的是Id）
            memberTypeList = baseMemberValidateService.getSubMemberTypeList(loginUser.getMemberType());
            //会员角色（按照Id升序排序）
            roleList = baseMemberValidateService.getSubRoleList(loginUser.getMemberType());
        }
        memberTypeList.add(0, new MemberTypeIdAndNameVO(0L, MemberStringEnum.CHOOSE.getName()));
        conditionVO.setMemberTypes(memberTypeList);
        roleList.add(0, new RoleIdAndNameVO(0L, MemberStringEnum.CHOOSE.getName()));
        conditionVO.setRoles(roleList);

        //会员等级
        List<LevelAndTagVO> levelList = baseMemberLevelConfigService.listSubMemberLevels(loginUser.getMemberId(), loginUser.getMemberRoleId());
        levelList.add(0, new LevelAndTagVO(0, MemberStringEnum.CHOOSE.getName()));
        conditionVO.setLevels(levelList);

        return Wrapper.success(conditionVO);
    }

    /**
     * 分页、模糊查询会员
     *
     * @param headers HttpHeaders信息
     * @param queryVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<PageData<MemberAssignedPageQueryVO>> pageMembers(HttpHeaders headers, MemberAbilityAssignedMemberQueryVO queryVO) {
        UserLoginCacheDTO loginUser = memberCacheService.needLoginFromBusinessPlatform(headers);

        Specification<MemberRelationDO> spec = (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            //上级会员id和角色Id
            list.add(criteriaBuilder.equal(root.get("memberId").as(Long.class), loginUser.getMemberId()));
            list.add(criteriaBuilder.equal(root.get("roleId").as(Long.class), loginUser.getMemberRoleId()));
            list.add(criteriaBuilder.equal(root.get("status").as(Integer.class), MemberStatusEnum.NORMAL.getCode()));
            //需要筛选出当前还没有被领取的下级会员数据   即上级用户id为null或者为0
            list.add(criteriaBuilder.or(root.get("userId").as(Long.class).isNull(), criteriaBuilder.equal(root.get("userId").as(Long.class), 0L)));

            //注册开始时间
            if (StringUtils.hasLength(queryVO.getStartDate())) {
                LocalDateTime startDate = LocalDateTime.parse(queryVO.getStartDate().concat(" 00:00:00"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createTime").as(LocalDateTime.class), startDate));
            }

            //注册结束时间
            if (StringUtils.hasLength(queryVO.getEndDate())) {
                LocalDateTime endDate = LocalDateTime.parse(queryVO.getEndDate().concat(" 23:59:59"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                list.add(criteriaBuilder.lessThanOrEqualTo(root.get("createTime").as(LocalDateTime.class), endDate));
            }

            //内部状态
            if (NumberUtil.isNullOrZero(queryVO.getInnerStatus())) {
                list.add(criteriaBuilder.notEqual(root.get("innerStatus").as(Integer.class), MemberInnerStatusEnum.NEW.getCode()));
            } else {
                list.add(criteriaBuilder.equal(root.get("innerStatus").as(Integer.class), queryVO.getInnerStatus()));
            }

            //外部状态
            if (NumberUtil.isNullOrZero(queryVO.getOuterStatus())) {
                list.add(root.get("outerStatus").as(Integer.class).in(outerStatusEnums.stream().map(MemberOuterStatusEnum::getCode).collect(Collectors.toList())));
            } else {
                list.add(criteriaBuilder.equal(root.get("outerStatus").as(Integer.class), queryVO.getOuterStatus()));
            }


            //会员状态
            if (NumberUtil.notNullOrZero(queryVO.getStatus())) {
                list.add(criteriaBuilder.equal(root.get("status").as(Integer.class), queryVO.getStatus()));
            }

            //会员角色
            if (NumberUtil.notNullOrZero(queryVO.getRoleId())) {
                list.add(criteriaBuilder.equal(root.get("subRoleId").as(Long.class), queryVO.getRoleId()));
            }

            //会员名称、注册来源
            if (StringUtils.hasLength(queryVO.getName()) || NumberUtil.notNullOrZero(queryVO.getSource())) {
                Join<Object, Object> subMemberJoin = root.join("subMember", JoinType.LEFT);
                if (StringUtils.hasLength(queryVO.getName())) {
                    list.add(criteriaBuilder.like(subMemberJoin.get("name").as(String.class), "%" + queryVO.getName().trim() + "%"));
                }

                if (NumberUtil.notNullOrZero(queryVO.getSource())) {
                    list.add(criteriaBuilder.equal(subMemberJoin.get("source").as(Integer.class), queryVO.getSource()));
                }
            }

            //会员等级
            if (NumberUtil.notNullOrZero(queryVO.getLevel())) {
                Join<Object, Object> levelRightJoin = root.join("levelRight", JoinType.LEFT);
                list.add(criteriaBuilder.equal(levelRightJoin.get("level").as(Integer.class), queryVO.getLevel()));
            }

            //会员类型
            if (NumberUtil.notNullOrZero(queryVO.getMemberTypeId())) {
                Join<Object, Object> memberTypeJoin = root.join("subRole", JoinType.LEFT);
                list.add(criteriaBuilder.equal(memberTypeJoin.get("memberType").get("id").as(Long.class), queryVO.getMemberTypeId()));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        Pageable page = PageRequest.of(queryVO.getCurrent() - 1, queryVO.getPageSize(), Sort.by("id").descending());
        Page<MemberRelationDO> pageList = relationRepository.findAll(spec, page);

        return Wrapper.success(new PageData<>(pageList.getTotalElements(), pageList.getContent().stream().map(relationDO -> {
            MemberAssignedPageQueryVO memberVO = new MemberAssignedPageQueryVO();
            memberVO.setMemberId(relationDO.getSubMember().getId());
            memberVO.setValidateId(relationDO.getId());
            memberVO.setName(relationDO.getSubMember().getName());
            memberVO.setMemberTypeName(MemberTypeEnum.getCodeMessage(relationDO.getSubRole().getMemberType().getTypeEnum()));
            memberVO.setRoleId(relationDO.getSubRoleId());
            memberVO.setRoleName(relationDO.getSubRoleName());
            memberVO.setSourceName(MemberRegisterSourceEnum.getCodeMessage(relationDO.getSubMember().getSource()));
            memberVO.setRegisterTime(relationDO.getCreateTime().format(ServiceConfig.DEFAULT_DATETIME_FORMATTER));
            memberVO.setLevel(relationDO.getLevelRight() == null ? 0 : relationDO.getLevelRight().getLevel());
            memberVO.setLevelTag(relationDO.getLevelRight() == null ? "" : relationDO.getLevelRight().getLevelTag());
            memberVO.setStatus(relationDO.getStatus());
            memberVO.setStatusName(MemberStatusEnum.getCodeMessage(relationDO.getStatus()));
            memberVO.setInnerStatus(relationDO.getInnerStatus());
            memberVO.setInnerStatusName(MemberInnerStatusEnum.getCodeMsg(relationDO.getInnerStatus()));
            memberVO.setOuterStatus(relationDO.getOuterStatus());
            memberVO.setOuterStatusName(MemberOuterStatusEnum.getCodeMsg(relationDO.getOuterStatus()));
            memberVO.setDepositTime(relationDO.getDepositTime() == null ? "" : relationDO.getDepositTime().format(ServiceConfig.DEFAULT_DATETIME_FORMATTER));
            return memberVO;
        }).collect(Collectors.toList())));
    }

    /**
     * 操作用户领取会员
     *
     * @param headers       Http头部信息
     * @param subMemberList 接口参数
     * @return 操作结果
     */
    @Override
    @Transactional
    public Wrapper<Void> bindOperator(HttpHeaders headers, List<SubMemberIdRoleIdVO> subMemberList) {
        UserLoginCacheDTO loginUser = memberCacheService.needLoginFromBusinessPlatform(headers);

        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (userDO.getUserAuth() == null) {
            return Wrapper.fail(ResponseCode.MC_MS_USER_AUTH_DOES_NOT_EXIST);
        }

        QMemberRelationDO qMemberRelationDO = QMemberRelationDO.memberRelationDO;
        List<Long> subMemberIdList = subMemberList.stream().map(SubMemberIdRoleIdVO::getSubMemberId).collect(Collectors.toList());
        List<Long> subMemberRoleIdList = subMemberList.stream().map(SubMemberIdRoleIdVO::getSubRoleId).collect(Collectors.toList());

        long count = jpaQueryFactory.select(qMemberRelationDO)
                .from(qMemberRelationDO)
                .where(qMemberRelationDO.memberId.eq(loginUser.getMemberId()))
                .where(qMemberRelationDO.roleId.eq(loginUser.getMemberRoleId()))
                .where(qMemberRelationDO.subMemberId.in(subMemberIdList))
                .where(qMemberRelationDO.subRoleId.in(subMemberRoleIdList))
                .where(qMemberRelationDO.userId.isNull().or(qMemberRelationDO.userId.eq(0L)))
                .where(qMemberRelationDO.relType.eq(MemberRelationTypeEnum.OTHER.getCode()))
                .fetchCount();

        if (subMemberList.size() != count) {
            throw new BusinessException(ResponseCode.MC_MS_MEMBER_RELATION_DOES_NOT_EXIST);
        }

        //置上级用户id为该操作用户id
        jpaQueryFactory.update(qMemberRelationDO)
                .where(qMemberRelationDO.memberId.eq(loginUser.getMemberId()))
                .where(qMemberRelationDO.roleId.eq(loginUser.getMemberRoleId()))
                .where(qMemberRelationDO.subMemberId.in(subMemberIdList))
                .where(qMemberRelationDO.subRoleId.in(subMemberRoleIdList))
                .where(qMemberRelationDO.userId.isNull().or(qMemberRelationDO.userId.eq(0L)))
                .where(qMemberRelationDO.relType.eq(MemberRelationTypeEnum.OTHER.getCode()))
                .set(qMemberRelationDO.userId, loginUser.getUserId())
                .execute();

        return Wrapper.success();
    }
}
